<?php
###
#  Baing PHP 框架 1.0.0
#  http://baing.co/
#
#  Copyright: 白晓阳
#  License: CC BY-NC-SA 4.0
#  https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh
###

namespace bai\feature;


trait Paths
{
    final public static function mapPath(string $path, string $pattern): ?array
    {
        static $wildcards = ['*', '.*', '**'];
        static $flags = ':*?';

        if ($pattern === $path) return [];
        if ($pattern[0] === '.' || !strpbrk($pattern, $flags)) return null;

        $pathPieces = explode('/', $path);
        $pathPieces = array_merge([], array_filter($pathPieces));
        $patternPieces = explode('/', $pattern);
        $patternPieces = array_merge([], array_filter($patternPieces));

        $params = [];
        for ($i = 0, $m = count($patternPieces), $n = count($pathPieces); $i < $m; $i++) {
            $item = $patternPieces[$i];
            if ($i >= $n) {
                if (in_array($item, $wildcards) || $item[-1] === '?') continue;
                return null;
            }
            if ($item === $pathPieces[$i]) continue;
            if ($item === '**') {
                $params = array_slice($pathPieces, $i);
                return $params;
            }
            if (in_array($item, $wildcards)) {
                $params[] = $pathPieces[$i];
                continue;
            }
            if ($item && $item[0] === ':') {
                $params[] = $pathPieces[$i];
                if (preg_match('/^:(?:<([a-zA-Z0-9]+)>)?([a-zA-Z0-9]+)\??$/', $item, $matches)) {
                    $field = $matches[2];
                    $params[$field] = $pathPieces[$i];
                    if ($matches[1]) {
                        $params[$matches[1]][$field] = $pathPieces[$i];
                    }
                    continue;
                }
                $field = preg_replace('/^:|<[a-zA-Z0-9]+>|\?$/', '', $item);
                $params[$field] = $pathPieces[$i];
                continue;
            }
            return null;
        }
        return $params;
    }

    final public static function sortPath(string $a, string $b): int
    {
        static $flags = ['', ':', '*'];

        $a = explode('/', $a);
        $b = explode('/', $b);
        $countA = count($a);
        $countB = count($b);
        for ($i = 0, $m = min($countA, $countB); $i < $m; $i++) {
            if ($a[$i] === $b[$i]) continue;
            $levelA = array_search($a[$i][0], $flags);
            $LevelB = array_search($b[$i][0], $flags);
            if ($levelA === $LevelB) continue;
            return $levelA > $LevelB ? 1 : -1;
        }
        return $countA < $countB ? 1 : -1;
    }

    final public static function filterPath(string $path): ?string
    {
        static $skip = ['', '.'];
        static $flags = '\/';

        if (!$path) return null;
        if (!str_contains($path, '..') || !strpbrk($path, $flags)) return $path;

        $path = str_replace('\\', '/', $path);
        $pieces = array_reverse(explode('/', $path));

        $filtered = [];
        $depth = 0;
        foreach ($pieces as $piece) {
            if (in_array($piece, $skip)) continue;
            if ($piece === '..') {
                $depth++;
                continue;
            }
            if ($depth > 0) {
                $depth--;
                continue;
            }
            $filtered[] = $piece;
        }
        if ($depth > 0) return null;

        $path = join('/', array_reverse($filtered));
        return $path ?: null;
    }
}
